/*
 * main.cpp
 *
 *  Created on: 01/06/2013
 *      Author: Jeffrey Alvarez Masson
 */

#include "SampleComplexType.h"
#include "ValidationScope.h"
#include "ValidationRule.h"
#include <stdexcept>
#include <iostream>

using namespace std;
using namespace ValidationRules;

DEFINE_RULE_ARGS(R1, "", obj1->stringField == arg1,
		SampleComplexType* obj1,
		std::string arg1);

DEFINE_RULE(R2, "", obj1->doubleField == 5.4,
		SampleComplexType* obj1)

DEFINE_RULE(R3, "", t.structPField != NULL,
		SampleComplexType t);

DEFINE_RULE(R4, "R3", t.structPField->tm_hour == 5,
		SampleComplexType t);

void ApplyWithScope(SampleComplexType& t,
		SampleComplexType& t2,
		SampleComplexType& t3) {

	cout << "Applying with scope..." << endl;
	ValidationScope scope;
	try {
		APPLY_RULE_ARGS(R1, &t, GO_ON, throw logic_error("R1 not accomplished"), "1");
	}
	catch (exception& ex) {
		cout << ex.what() << endl;
	}
	FOREACH_APPLY_RULE(t.vectorOfPtrField, SampleComplexType* ct,
		APPLY_RULE(R2, ct, cout << "R2 applied: " << ct->structField.tm_min << endl,
				throw logic_error("R1 not accomplished")));
	cout << "Last validation of rule R1 was " <<
		VRE(R1) << endl;
	cout << "Last validation of rule R2 was " <<
		VRE(R2) << endl;
	cout << "Rule R2 has been applied " <<
		VRG(R2)->GetTimesApplied() << " times." << endl;
}

int main(int argc, char** args) {
	SampleComplexType t, t2, t3;
	t.doubleField = 5.4;
	memcpy(&t2, &t, sizeof(SampleComplexType));
	memcpy(&t3, &t, sizeof(SampleComplexType));

	t.stringField = "0";
	t.structField.tm_min = 0;
	t2.structField.tm_min = 1;
	t3.structField.tm_min = 2;

	t.vectorOfPtrField.push_back(&t);
	t.vectorOfPtrField.push_back(&t2);
	t.vectorOfPtrField.push_back(&t3);

	try {
		APPLY_RULE_ARGS(R1, &t, cout << "R1 accomplished" << endl, throw logic_error("R1 not accomplished"), "0");
		APPLY_RULE_ARGS(R1, &t, GO_ON, throw logic_error("R1 not accomplished"), "1");
	}
	catch (exception& ex) {
		cout << "Error: " << ex.what() << endl;
	}
	try {
		APPLY_RULE(R4, t, GO_ON, throw logic_error("R4 not accomplished"));
	}
	catch (exception& ex) {
		cout << "Error: " << ex.what() << endl;
	}
	FOREACH_APPLY_RULE(t.vectorOfPtrField, SampleComplexType* ct,
		APPLY_RULE(R2, ct, cout << "R2 applied" << endl,
				throw logic_error("R1 not accomplished")));

	for (RuleMap::const_iterator iter = ValidationScope::GetCurrent()->GetRules()->begin();
		iter != ValidationScope::GetCurrent()->GetRules()->end(); ++iter) {
		cout << "Regla " << iter->first << ": " <<
			iter->second->GetRuleExpression() << endl;
	}
	cout << "Last validation of rule R1 was " <<
			VRG(R1)->GetLastValidationResult() << endl;
	cout << "Last validation of rule R2 was " <<
			VRG(R2)->GetLastValidationResult() << endl;

	APPLY_RULE_EXPR(VRE(R1) && VRE(R2),
			cout << "R1 and R2 = true" << endl,
			cout << "R1 and R2 = false" << endl);

	APPLY_RULE_EXPR(VRE(R1) || VRE(R2),
			cout << "R1 or R2 = true" << endl,
			cout << "R1 or R2 = false" << endl);

	cout << "Rule R2 has been applied " <<
			VRG(R2)->GetTimesApplied() << " times." << endl;

	ApplyWithScope(t, t2, t3);
}
